import subprocess
import re
from optparse import OptionParser

long_short = {"write_limit":"-wl",
              "memory_limit":"-ml",
              "deadline":"-d",
              "time_limit":"-tl",
              "load_ratio_limit":"-lr",
              "working_dir":"-wd",
              "silent":"--silent",
              "debug":"--debug",
              "user":"-u",
              "password":"-p",
              }

long_short_alt = {"write_limit":"-wl",
              "memory_limit":"-ml",
              "deadline":"-d",
              "time_limit":"-tl",
              "load_ratio_limit":"",
              "working_dir":"",
              "silent":"",
              "debug":"",
              "user":"-u",
              "password":"-p",
              }
terminate_reason = {"ExitProcess":"FINISHED_NORMAL|NOT_TERMINATED",
                    "MemoryLimitExceeded":"FINISHED_TERMINATED|MEMORY_LIMIT",
                    "TimeLimitExceeded":"FINISHED_TERMINATED|TIME_LIMIT",
                    "WriteLimitExceeded":"FINISHED_TERMINATED|WRITE_LIMIT",
                    "AbnormalExitProcess":"FINISHED_ABNORMALLY|NOT_TERMINATED"}
class SpawnerReport:
    processor_time=0.0
    user_time=0.0
    memory_used=0.0
    written=0.0
    load_ratio=0.0
    terminate_reason=""
    exit_status=""
    exit_code=0
    exception=""
    exception_interpretation=""
    cmd = ""
    output = ""
    def format_argument(self, argument, value, delimeter="="):
        if delimeter != "=" and long_short_alt[argument] == "":
            return ""
        if value == True:
            return "%s" % long_short[argument]
        return '%s%s%s' % (long_short[argument], delimeter, value)
    def __init__(self, opts, arguments="", tester=""):
        if tester == "":
            tester_arguments = " ".join([(self.format_argument(key, val)) for key, val in opts.items()])
        else:
            tester_arguments = " ".join([(self.format_argument(key, val, ":")) for key, val in opts.items()])
        program = "%s %s" % (options.program, arguments)
        if tester == "":
            tester = options.tester
        self.cmd = ("%s") % (tester)
        print tester_arguments
        if len(opts):
            self.cmd = ("%s %s") %(self.cmd, tester_arguments)
        self.cmd = ("%s %s") %(self.cmd, program)
        self.cmd = self.cmd.replace("/", "\\")
# self.cmd = ("%s %s %s" % (tester, tester_arguments, program)).replace('/', '\\') #for win
        print self.cmd
        self.output = subprocess.check_output(self.cmd)
        f = open("%s/test_%s.txt" % (options.builddir, options.name), "w")
        f.write("%s\n%s" % (self.cmd, self.output))
        f.close()
        get_number = lambda name: float(re.search(r'%s:\s+([0-9.\-]*)' % name,self.output).group(1))
        get_string = lambda name, prefix="": re.search(r'%s:\s*%s([\w]*)' % (name, prefix),self.output, re.I|re.M).group(1)
        self.memory_used = get_number("PeakMemoryUsed")
        self.written = get_number("Written")
        if tester == options.tester:
            self.processor_time = get_number("ProcessorTime")
            self.user_time = get_number("UserTime")
            self.load_ratio = get_number("LoadRatio")
            self.exit_code = get_number("ExitCode")

            self.terminate_reason = get_string("TerminateReason", "TERMINATE_REASON_")
            self.exit_status = get_string("ExitStatus", "PROCESS_")
            self.exception = get_string("Exception", "EXCEPTION_")
            self.exception_interpretation = get_string("ExceptionInterpretation")
        else:
            self.processor_time = get_number("UserTime")
            self.terminate_reason = get_string("TerminateReason", "")
            self.exit_status = get_string("ExitStatus", "")

class Test:
    options = {}
    test_name = ""
    def __init__(self, _options, _test_name=""):
        if _test_name == "":
            _test_name = str(self.__class__.__name__)
        self.test_name = _test_name
        self.options = _options
    def check(self, val1, val2, message='Expected %s : Received %s'):
        msg = message
        print (msg) % (val1, val2)
        if val1 != val2:
            raise (message % (val1, val2))
    def test(self):
        return "ok"
    def runsp(self, _options={}, arguments=""):
        return SpawnerReport(_options, arguments, "")
    def runasp(self, _options={}, arguments=""):
        return SpawnerReport(_options, arguments, options.atester)

class result_test(Test):
    conditions = {}
    arguments = ""
    def __init__(self, _options, _conditions, arguments="", test_name=""):
        Test.__init__(self, _options, test_name)
        self.options['silent'] = True
        self.options['working_dir'] = options.workdir
        self.arguments = arguments
        self.conditions = _conditions
    def test(self):
        report = self.runsp(self.options, arguments=self.arguments)
        if 'terminate_reason' in self.conditions:
            self.check(report.terminate_reason, self.conditions['terminate_reason'])
        if 'exception' in self.conditions:
            self.check(report.exception, self.conditions['exception'])
        if 'exit_status' in self.conditions:
            self.check(report.exit_status, self.conditions['exit_status'])


class Tests:
    tests = []
    def __init__(self, _tests):
        self.tests = _tests
    def list(self):
        print ';'.join([(test.test_name) for test in self.tests])
    def perform(self, index):
        ind = int(index)
        if ind >= 0 and ind < len(self.tests):
            self.tests[ind].test()
        else:
            raise 'Wrong index %s' % index

def use_tests(tests):
    if options.list:
        tests.list()
        exit()
    tests.perform(options.index)

parser = OptionParser()
parser.add_option("--wl", "--writelimit", dest="writelimit", default="inf")
parser.add_option("--tl", "--timelimit", dest="timelimit", default="inf")
parser.add_option("--ml", "--memorylimit", dest="memorylimit", default="inf")
parser.add_option("-d", "--deadline", dest="deadline", default="inf")
parser.add_option("--lr", "--loadratio", dest="loadratio", default="inf")

parser.add_option("--wd", "--workdir", dest="workdir")
parser.add_option("--bd", "--builddir", dest="builddir")
parser.add_option("-s", "--silent", dest="silent", default="false")

parser.add_option("--tester", dest="tester", default="")
parser.add_option("--atester", dest="atester", default="")
parser.add_option("-n", "--name", dest="name", default="")
parser.add_option("-p", "--program", dest="program", default="")
parser.add_option("-a", "--arguments", dest="arguments", default="")

parser.add_option("--list", action="store_true", dest="list", default=False)
parser.add_option("--test", dest="index", default="0")

(options, args) = parser.parse_args()

